package Logikk;

import Beans.Deltaker;
import Beans.Klasse;
import Beans.Lop;
import Beans.Resultat;
import DB.DBehandler;
import Beans.Admin;
import java.io.IOException;
import java.io.Serializable;
import java.security.Principal;
import java.sql.Time;
import java.util.ArrayList;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;

/**
 * Klasse som tar seg av registreringen, og er den øverste problemdomeneklassen vår
 * @author Gruppe1
 */
@SessionScoped
@ManagedBean(name = "rb")
public class RegistreringsBean implements Serializable {

    private AlleDeltakere deltakere = new AlleDeltakere();
    private AlleLop lopene = new AlleLop();
    private AlleResultat alleResultat = new AlleResultat();
    private DBehandler db = new DBehandler();
    @Inject Lop lopet;
    private Klasse klasse = new Klasse();
    private Resultat resultat = new Resultat();
    @Inject Deltaker enDeltaker = new Deltaker();
    private boolean bruker = false;
    private boolean admin = false;
    private boolean edit_admin = false;
    private Admin ad = new Admin();
    private String gmlPassord = "";

    /**
     * Hent DBehandler 
     * @return DBehandler konstant
     */
    public DBehandler getDb() {
        return db;
    }

    /**
     * Hent det gammle passordet til en bruker
     * @return det gamle passordet
     */
    public String getGmlPassord() {
        return gmlPassord;
    }
    /**
     * Sjekker hvilken bruker som er logget inn og henter ut de løpene som denne brukeren ikke er registrert på
     * @return ArrayList med Objekt av typen Lop (OBS! returnerer kun de løpene den påloggede deltakeren ikke er registrert på, system får ut alle).
     */
    public ArrayList<Lop> hentBrukerLop(){
        FacesContext context = FacesContext.getCurrentInstance();
        Principal p = context.getExternalContext().getUserPrincipal();
        String epost = p.getName();
        return db.finnBrukerLop(db.finnDeltakerIdEpost(epost));
    }

    /**
     * Sett det gamle passordet
     * @param gmlPassord
     */
    public void setGmlPassord(String gmlPassord) {
        this.gmlPassord = gmlPassord;
    }
    /**
     * Bytt passordet til en deltaker
     * @return true hvis byttingen av passordet gikk bra
     */
    public boolean byttPassord(){
        if(!enDeltaker.sjekkPassord().equals("Passord OK")) return false;
        return db.sjekkBruker(enDeltaker.getEpost(), gmlPassord, enDeltaker.getPassord1());
    }
    private void cleanUp() {
        lopet = new Lop();
        klasse = new Klasse();
        resultat = new Resultat();
        enDeltaker = new Deltaker();
    }


    /**
     * En metode som er true hvis administrator kan editere
     * @return true hvis admin kan editere, false hvis ikke
     */
    public boolean isEdit_admin() {
        return edit_admin;
    }

    /**
     * Setter boolean slik at man kan få editere eller ikke
     * @param edit_admin
     */
    public void setEdit_admin(boolean edit_admin) {
        this.edit_admin = edit_admin;
    }
    

    /**
     * Konstrukøtren til registreringsbean, innehar metoden oppdater
     * @param brukernavn
     */
    public RegistreringsBean(String brukernavn) {
        //Hent inn all data!
        oppdater();
    }

    /**
     * Konstruktøren til regisreringsbean, innehar metoden oppdater
     */
    public RegistreringsBean() {
        oppdater();
    }

    /**
     * en metode som viser alle deltakerene 
     */
    public void visAlle() {
        alleResultat.def = new Lop(0, "", null, 0.0, "");
    }

    /**
     * Metode som oppdaterer løpene, deltakerene og resultatene
     */
    public void oppdater() {
        lopene.alleLop = db.finnAlleLop();
        deltakere.alleDeltakere = db.hentAlleDeltakere();
        ArrayList<Resultat> res = alleResultat.hentResultat();
        ad.setForrord(db.hentAdminData("forrord"));
        for (int i = 0; i < alleResultat.resultat.size(); i++) {
            for (Resultat r : res) {
                if (alleResultat.resultat.get(i).equals(r)) {
                    r.setEditable(alleResultat.resultat.get(i).isEditable());
                }
            }
        }
        alleResultat.resultat = res;
    }

    /**
     * Metode som lagrer resultatene i alleResultat
     * @return null
     */
    public String save() {
        alleResultat.save();
        return null;
    }

    /**
     * Metode som returnerer en konstant til Adminklassen
     * @return konstant til Administrator
     */
    public Admin getAd() {
        return ad;
    }

    /**
     * Metode som setter konstanten til klassen Admin
     * @param ad
     */
    public void setAd(Admin ad) {
        this.ad = ad;
    }
    
    /**
     * Metode som lagrer forrordet på index-siden
     */
    public void saveForrord(){
        db.lagreAdminData("forrord", ad.getForrord());
    }
    
    /**
     * Metode som henter forrordet 
     * @return forrordet som er lagret i databasen
     */
    public String hentForrord(){
        ad.setForrord(db.hentAdminData("forrord"));
        return db.hentAdminData("forrord");
    }

    /**
     * Metode som finner gjennomsnittstiden på løpet
     * @return gjennomsnittstiden
     */
    public Time ant() {
        Time tiden = db.finnGjennomsnittLop(alleResultat.def.getLop_id());
        return tiden;
    }

    /**
     * Hent resultatene fra AlleResultat
     * @return arrayList med alleResultat
     */
    public AlleResultat getResultatene() {
        return alleResultat;
    }

    /**
     * Setter resultatene til alle resultat
     * @param a
     */
    public void setResultatene(AlleResultat a) {
        alleResultat = a;
    }

    /**
     * Henter et resultat 
     * @return et resultat
     */
    public Resultat getResultatet() {
        return resultat;
    }

    /**
     * Sett et resultat
     * @param r
     */
    public void setResultatet(Resultat r) {
        resultat = r;
    }

    /**
     * Hent en deltaker fra Deltaker
     * @return en deltaker
     */
    public Deltaker getEnDeltaker() {
        return enDeltaker;
    }

    /**
     * Sett en deltaker
     * @param enDeltaker
     */
    public void setEnDeltaker(Deltaker enDeltaker) {
        this.enDeltaker = enDeltaker;
    }

    /**
     * Sett flere deltakere
     * @param ad
     */
    public void setDeltakere(AlleDeltakere ad) {
        deltakere = ad;
    }

    /**
     * Hent flere deltakere
     * @return hent deltakere fra AlleDeltakere
     */
    public AlleDeltakere getDeltakere() {
        return deltakere;
    }

    /**
     * Sett et Løp
     * @param l
     */
    public void setLopet(Lop l) {
        lopet = l;
    }

    /**
     * Hent et løp
     * @return løpet
     */
    public Lop getLopet() {
        return lopet;
    }

    /**
     * Sett flere løp
     * @param l
     */
    public void setLopene(AlleLop l) {
        lopene = l;
    }

    /**
     * Hent flere løp
     * @return alle løpene
     */
    public AlleLop getLopene() {
        return lopene;
    }

    /**
     * Registrer resultat med tid, deltaker, løp, klasse, samt oppdaterer
     * @return true hvis registreringen gikk bra, false hvis ikke
     */
    public boolean registrerResultat() {

        if (!db.registrerResultat(resultat.getStartNr(), resultat.getLop().getLop_id(), resultat.getTid())) {
            return false;
        }

        Time tid = resultat.getTid();
        Deltaker d = db.finnDeltaker(resultat.getLop().getLop_id(), resultat.getStartNr());
        Lop l = db.finnLop(resultat.getLop().getLop_id());
        Klasse k = db.finnKlasse(resultat.getLop().getLop_id(), resultat.getStartNr());
        boolean ok = alleResultat.leggTilResultat(new Resultat(d, k, l, tid), resultat.getStartNr(), resultat.getLop().getLop_id());
        oppdater();
        return ok;
    }

    private boolean finnesLop(Lop l) {
        for (Lop lop : lopene.alleLop) {
            if (lop.getLopnavn().equals(l.getLopnavn())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Registrer ett nyttløp
     * @return tekst der det står reg_lop_OK eller reg_lop_feil!
     */
    public String regLop() {
        if (finnesLop(lopet)) {
            return null;
        }
        int nr = db.registrerNyttLop(lopet);
        if (nr < 0) {
            return null;
        }
        Lop l = null;
        if (lopet != null) {
            l = new Lop(nr, lopet.getLopnavn(), lopet.getDate(), lopet.getDistanse(), lopet.getBeskrivelse());
        }

        //cleanUp();

        return lopene.leggTilLop(l);
    }

    /**
     * Metode som finner ut om eposten er registrert fra før
     * @param epost
     * @return true hvis eposten finnes fra før
     */
    public boolean finnesEpost(String epost) { //sjekker om eposten finnes fra før i Arraylisten med deltakere
        for (int i = 0; i < deltakere.alleDeltakere.size(); i++) {
            if (epost.equals(deltakere.alleDeltakere.get(i).getEpost())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Hent klasse
     * @return en klasse
     */
    public Klasse getKlasse() {
        return klasse;
    }

    /**
     * Setter en klasse
     * @param klasse
     */
    public void setKlasse(Klasse klasse) {
        this.klasse = klasse;
    }

    /**
     * Metode som sorterer resultatene etter klasse
     */
    public void sorterEtterKlasser() {
        alleResultat.sorterEtterKlasse(alleResultat.def.getLop_id());
    }

    /**
     * Metode som sorterer resultatene etter tid
     */
    public void sorterEtterTid() {
        alleResultat.sorterEtterTid(alleResultat.def.getLop_id());
    }

    /**
     * Metode som registrerer ny deltaker
     * @return string med deltaker_finnes_fra_før/legg_til_deltaker_OK/legg_til_deltaker_ikke_ok
     */
    public String nyDeltaker() {
        String p = sjekkPassord();
        if(!p.equals("Passord OK")) return p;
        
        if (finnesEpost(enDeltaker.getEpost())) return "deltaker_finnes_fra_for";
        
        int nr = db.registrerNyDeltaker(enDeltaker);
        if (nr < 0) return null;
        
        Deltaker d = null;
        if (enDeltaker != null) d = new Deltaker(enDeltaker.getFnavn(), enDeltaker.getEnavn(), enDeltaker.getEpost(), enDeltaker.getAdresse(), enDeltaker.getFaar(), enDeltaker.getKjonn(), nr);

        return deltakere.leggTilDeltaker(d);
    }

    /**
     * Sett klasse med alders_inndeling og kjønn
     */
    public void setKlasse() {
        klasse = db.identifiserKlasse(klasse.getAlder_inndeling(), klasse.getKjonn());
    }

    /**
     * Registrer ny deltaker på løp
     * @return string med reg_ikke_OK eller reg_OK
     */
    public String regDeltakerPaaLop() {
        setKlasse();
        int nr = db.registrerDeltakerPaaLop(lopet.getLop_id(), enDeltaker.getDeltaker_id(), klasse.getId());
        if (nr <= 0) {
            return "reg_ikke_OK";
        }
        alleResultat.leggTilDeltaker(enDeltaker, lopet, klasse, nr);
        resultat = new Resultat(enDeltaker, klasse, lopet, nr);

        return "reg_OK";
    }

    /**
     * Metode som finner ut hvilken rolle som er logget inn
     * @return string med "ikke_logget_inn / bruker / sys"
     */
    public String getUserPrincipalName() {
        FacesContext context = FacesContext.getCurrentInstance();
        Principal p = context.getExternalContext().getUserPrincipal();
        if (p == null) {
            admin = false;
            bruker = false;
            return "";
        }
        if (p.getName().equals("sys")) {
            admin = true;
            bruker = true;
            
        } else if (p != null) {
            admin = false;
            bruker = true;
        }
        return p.getName();
    }

    /**
     * Metode som logger ut en bruker/sys som er logget inn
     * @throws IOException
     */
    public void logut() throws IOException {
        FacesContext fc = FacesContext.getCurrentInstance();
        HttpSession s = (HttpSession) fc.getExternalContext().getSession(false);
        s.invalidate();
        FacesContext.getCurrentInstance().getExternalContext().redirect("faces/index.xhtml");
    }

    /**
     * Metode som sjekker om det er bruker som er logget inn
     * @return true dersom det er en bruker som er logget inn
     */
    public boolean sjekkBruker() {
        return bruker;
    }

    /**
     * Metode som sjekker om administrator er logget inn
     * @return true hvis admin er logget inn
     */
    public boolean sjekkAdmin() {
        return admin;
    }

    /**
     * Metode som sjekker passordet til en deltaker
     * @return string med passord_ok eller passordet_stemmer_ikke
     */
    public String sjekkPassord(){
        return enDeltaker.sjekkPassord();
    }
}
